#include "log.hpp"
#include "Socket.hpp"
#include <sys/select.h>
#include <sys/epoll.h>

const int default_fd = -1;
const int N = 128;
const int wait_time = 1000;
const int arr_size = 1024;

class server
{
public:
    server(const add_in &addr)
    {
        _listen_fd = make_shared<Tcp_socket>();
        _listen_fd->Bulid_Server(addr);

        cout << "Tis" << endl;

        _epoll_fd = epoll_create(N);
        if (_epoll_fd == default_fd)
        {
            log(FATAL, "epoll create fail");
            exit(1);
        }

        int n = 0;
        epoll_event event;
        event.events = EPOLLIN;
        event.data.fd = _listen_fd->get_sockfd();
        n = epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, _listen_fd->get_sockfd(), &event);
        if (n == -1)
        {
            log(FATAL, "epoll_ctl error");
            exit(2);
        }
    }

    ~server()
    {
        _listen_fd->Close();
        if (_epoll_fd > 0)
        {
            close(_epoll_fd);
        }
    }

    void Run()
    {
        while (1)
        {
            int n = epoll_wait(_epoll_fd, arr, N, wait_time);
            switch (n)
            {
            case 0:
                log(DEBUG, "time out");
                break;
            case -1:
                log(FATAL, "epoll_wait");
                break;
            default:
                log(DEBUG, "%d file is OK", n);
                Loop(n);
                break;
            }
        }
    }

    void Loop(int sum)
    {
        for (int i = 0; i < sum; i++)
        {
            // 只处理读
            if (EPOLLIN & arr[i].events)
            {
                if (arr[i].data.fd == _listen_fd->get_sockfd())
                {
                    // listen套接字,水平工作模式
                    sockaddr_in tmp;
                    int newfd = _listen_fd->Accept_socket(&tmp);
                    add_in addr(tmp);
                    log(DEBUG, "new link come IP: %s, PORT: %d", addr.get_ip().c_str(), addr.get_port());

                    // 将新来的fd 添加入epoll，只关注读
                    epoll_event ev;
                    ev.data.fd = newfd;
                    ev.events = EPOLLIN;
                    epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, newfd, &ev);
                }
                else
                {
                    // 普通套接字，将发来的消息不变返回
                    int fd = arr[i].data.fd;
                    char fd_arr[arr_size] = {0};
                    int n = recv(fd, fd_arr, arr_size - 1, 0);
                    switch (n)
                    {
                    case 0:
                        log(DEBUG, "fd: %d unlinke", fd);
                        close(fd);
                        break;
                    case -1:
                        log(DEBUG, "recv error", fd);
                        break;
                    default:
                        fd_arr[n] = 0;
                        string str = "server echo: ";
                        str += fd_arr;
                        cout << str;
                        send(fd, str.c_str(), str.size(), 0);
                        break;
                    }
                }
            }
        }
    }

private:
    socket_ptr _listen_fd;
    int _epoll_fd;
    epoll_event arr[N];
};
